﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Savannah.Core
{
    /// <summary>
    /// Vegetáriánusok ősosztálya
    /// A vegetáriánusok közös tulajdonságait és viselkedésformáit tartalmazza.
    /// </summary>
    public abstract class Vegetarian : AnimalBase
    {

        /// <summary>
        /// Az állat ezzel a metódussal dönti el mit csináljon, ha az adott napon rá kerül a sor és végrehajtja a kiválasztott műveletet
        /// </summary>
        /// <param name="pMap">ez az állat körüli "élettér"</param>
        internal override void Live(ref Cell[,] pMap)
        {
            Cell tempCell = null;

            foreach (Cell item in pMap)
            {
                if (item.CoordX == xCoordinate && item.CoordY == yCoordinate)
                {
                    tempCell = item;
                    break;
                }
            }   

            if (HungerLevel < 5)
            {
                if (this.Graze(ref tempCell))
                {                   
                    CurrentAge++;
                    HungerLevel--;

                    return;
                }
               
            }

            if (canReproduce(tempCell))
            {
                if (Reproduce(ref tempCell))
                {
                    CurrentAge++;
                    HungerLevel--;

                    return;
                }
            }

            Move(ref pMap);

            CurrentAge++;
            HungerLevel--;
        }

        /// <summary>
        /// Move metódus implementációja növényevőknek
        /// </summary>
        /// <param name="possibleCells">A cellák, amiket az állat lát</param>
        internal override void Move(ref Cell[,] possibleCells)
        {
            Cell toCell = null;

            if (targetCell != null)
            {
                toCell = targetCell;
                DoTheMove(ref toCell, ref possibleCells);
                targetCell = null;

                return;
            }
            else
            {
                toCell = HungerLevel > 3 ? ChooseCellForReproduce(possibleCells) : ChooseCell(ref possibleCells);
            }


            DoTheMove(ref toCell, ref possibleCells);
        }

        /// <summary>
        /// ChooseCell fv. implementációja növényevőknek
        /// </summary>
        /// <param name="possibleCells">Ezekből a cellákból válogat</param>
        /// <returns>A cella amire majd megpróbál lépni</returns>
        protected override Cell ChooseCell(ref Cell[,] possibleCells)
        {
            Cell maxcell = null;

            foreach (Cell currentCell in possibleCells)
            {
                if (currentCell.CoordX == xCoordinate && currentCell.CoordY == yCoordinate)
                {
                    maxcell = currentCell;
                }
            }

            int maxp = int.MinValue;
            int temp;
            foreach (Cell actCell in possibleCells)
            {
                if ((actCell.GetAnimalList().Where(x=>x is Predator).Count())<=0)
                {
                    temp = CalculatePoints(actCell);
                    if (temp > maxp)
                    {
                        maxp = temp;
                        maxcell = actCell;
                    }
                }
            }

            return maxcell;
        }

        /// <summary>
        /// A Calculate fv. implemetációja növényevőknek
        /// </summary>
        /// <param name="pCell"></param>
        /// <returns></returns>
        protected override int CalculatePoints(Cell pCell)
        {
            try
            {
                if (pCell.GetAnimalList().Count > 4 || pCell.GetAdultNumber() > 1)
                {
                    return -1;
                }

                if (pCell.Plantp == null) {
                    return -1;
                }

                return (int)(pCell.Plantp.PlantSize * HungerLevel / GetDistance(pCell, new Cell(xCoordinate, yCoordinate)));
            }
            catch(DivideByZeroException)
            {
                return 0;
            }
        }

        /// <summary>
        /// A DoTheMove metódus implementációja a vegetáriánusoknak.
        /// </summary>
        /// <param name="fromCell"></param>
        /// <param name="toCell"></param>
        protected override void DoTheMove(ref Cell pTo, ref Cell[,] pMap)
        {
            if (pTo == null)
            {
                return;
            }


            if (xCoordinate - RangeOfMove > pTo.CoordX && yCoordinate - RangeOfMove > pTo.CoordX)
            {
                Savannah.savannah[xCoordinate - RangeOfMove, yCoordinate - RangeOfMove].AddAnimal(this);
                Savannah.savannah[xCoordinate, yCoordinate].RemoveAnimal(this);
                xCoordinate -= RangeOfMove;
                yCoordinate -= RangeOfMove;

                targetCell = pTo;
                return;
            }

            if (xCoordinate + RangeOfMove < pTo.CoordX && yCoordinate + RangeOfMove < pTo.CoordY)
            {
                Savannah.savannah[xCoordinate + RangeOfMove, yCoordinate + RangeOfMove].AddAnimal(this);
                Savannah.savannah[xCoordinate, yCoordinate].RemoveAnimal(this);
                xCoordinate += RangeOfMove;
                xCoordinate += RangeOfMove;

                targetCell = pTo;
                return;
            }

            if (yCoordinate - RangeOfMove > pTo.CoordY && xCoordinate + RangeOfMove < pTo.CoordX)
            {
                Savannah.savannah[xCoordinate + RangeOfMove, yCoordinate - RangeOfMove].AddAnimal(this);
                Savannah.savannah[xCoordinate, yCoordinate].RemoveAnimal(this);
                yCoordinate -= RangeOfMove;
                xCoordinate += RangeOfMove;

                targetCell = pTo;
                return;
            }

            if (yCoordinate + RangeOfMove < pTo.CoordY && xCoordinate - RangeOfMove > pTo.CoordX)
            {
                Savannah.savannah[xCoordinate - RangeOfMove, yCoordinate + RangeOfMove].AddAnimal(this);
                Savannah.savannah[xCoordinate, yCoordinate].RemoveAnimal(this);
                yCoordinate += RangeOfMove;
                xCoordinate -= RangeOfMove;

                targetCell = pTo;
                return;
            }

            if (xCoordinate - RangeOfMove > pTo.CoordX) 
            {
                Savannah.savannah[xCoordinate - RangeOfMove, yCoordinate].AddAnimal(this);
                Savannah.savannah[xCoordinate, yCoordinate].RemoveAnimal(this);
                xCoordinate -= RangeOfMove;
                yCoordinate = pTo.CoordY;

                targetCell = pTo;
                return;
            }

            if (xCoordinate + RangeOfMove < pTo.CoordX)
            {
                Savannah.savannah[xCoordinate + RangeOfMove, yCoordinate].AddAnimal(this);
                Savannah.savannah[xCoordinate, yCoordinate].RemoveAnimal(this);
                xCoordinate += RangeOfMove;
                yCoordinate = pTo.CoordY;

                targetCell = pTo;
                return;
            }
           
            if (yCoordinate - RangeOfMove > pTo.CoordY)
            {
                Savannah.savannah[xCoordinate, yCoordinate - RangeOfMove].AddAnimal(this);
                Savannah.savannah[xCoordinate, yCoordinate].RemoveAnimal(this);
                yCoordinate -= RangeOfMove;
                xCoordinate = pTo.CoordX;

                targetCell = pTo;
                return;
            }
            
            if (yCoordinate + RangeOfMove < pTo.CoordY)
            {
                Savannah.savannah[xCoordinate, yCoordinate + RangeOfMove].AddAnimal(this);
                Savannah.savannah[xCoordinate, yCoordinate].RemoveAnimal(this);
                yCoordinate += RangeOfMove;
                xCoordinate = pTo.CoordX;

                targetCell = pTo;
                return;
            }


            pTo.AddAnimal(this);

            Savannah.savannah[xCoordinate, yCoordinate].RemoveAnimal(this);
            xCoordinate = pTo.CoordX;
            yCoordinate = pTo.CoordY;
            targetCell = null;
        }

        /// <summary>
        /// Megadja a két cella távolságát(ha x-táv nagyobb akkor azt, ellenkező esetben y-távot)
        /// </summary>
        protected int GetDistance(Cell Cell1, Cell Cell2)
        {
            int dX = Math.Abs(Cell1.CoordX - Cell2.CoordX);
            int dY = Math.Abs(Cell1.CoordY - Cell2.CoordY);

            return dX > dY ? dX : dY;
        }

        /// <summary>
        /// A növényevő példány ezzel a metódussal iszik
        /// </summary>
        /// <param name="thisCell"></param>
        internal override void Drink(ref Cell thisCell)
        {
            if(thisCell.CellType == FieldType.water && /*thisCell.CellType == WaterDepth.shallow &&*/ this.ThirstyLevel > 4)
            {
                List<AnimalBase> animals = new List<AnimalBase>(thisCell.GetAnimalList());
                int i = 0;
                while(i < animals.Count && !(animals[i] is Predator)) { i++; }
                if (i == animals.Count)
                {
                    this.ThirstyLevel = 0;
                }
            }
        }
    }
}
